/*
 *
 *  *    Copyright © OpenAtom Foundation.
 *  *
 *  *    Licensed under the Apache License, Version 2.0 (the "License");
 *  *    you may not use this file except in compliance with the License.
 *  *    You may obtain a copy of the License at
 *  *
 *  *         http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  *    Unless required by applicable law or agreed to in writing, software
 *  *    distributed under the License is distributed on an "AS IS" BASIS,
 *  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  *    See the License for the specific language governing permissions and
 *  *    limitations under the License.
 *
 */

package com.inspur.edp.cef.engine.core.common;

import com.inspur.edp.cef.designtime.api.IGspCommonDataType;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.util.MetadataUtil;
import com.inspur.edp.cef.entity.entity.ICefData;
import com.inspur.edp.cef.entity.entity.IValueObjData;

import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.metadata.rtcustomization.api.CustomizationRtService;
import com.inspur.edp.udt.designtime.api.entity.UnifiedDataTypeDef;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Stream;

public class CefDataTypeUtil {

  public static IGspCommonField checkElementExists(IGspCommonDataType node, String labelId,
      Predicate<IGspCommonField> elementPredicate) {
    Objects.requireNonNull(labelId, "labelId");

    IGspCommonField element = findElement(node, labelId);
    if (element == null || (elementPredicate != null && !elementPredicate.test(element))) {
      throwElementNotFound(node, labelId);
    }
    return (IGspCommonField) element;
  }

  public static boolean isElementExist(IGspCommonDataType node, String labelId,
      Predicate<IGspCommonField> elementPredicate) {
    IGspCommonField element = findElement(node, labelId);
    return element != null && (elementPredicate == null || elementPredicate.test(element));
  }

  private static IGspCommonField findElement(IGspCommonDataType node, String labelId) {
    return (IGspCommonField) node.getContainElements().getByLabelId(labelId);
  }

  public static IGspCommonField checkElementValue(IGspCommonDataType node, String labelId,
      Object value, Predicate<IGspCommonField> elementPredicate) {
    IGspCommonField element = checkElementExists(node, labelId, elementPredicate);

    if (element.getIsUdt()) {
      if (value != null && !(value instanceof IValueObjData)) {
        throwInvalidPropertyValue(node, element, value);
      }
    }
//    else if (element.getObjectType() == GspElementObjectType.Association) {
//      if (value != null) {
//        if (value instanceof AssociationInfo) {
//          GspAssociation association = element.getChildAssociations().get(0);
//          ((AssociationInfo) value).setAssociation(association);
//          for (Map.Entry<String, Object> key : ((AssociationInfo) value).getValues()
//              .entrySet()) {
//            checkRefElementExists(association, key.getKey());
//            //TODO:check key.getValue()
//          }
//        } else {
//          throwInvalidPropertyValue(node, element, value);
//        }
//      }
//    }
    return element;
    //TODO: check enum/normal
  }

  private static void throwInvalidPropertyValue(IGspCommonDataType node, IGspCommonField element,
      Object value) {
    throw new RuntimeException(
        (value != null ? value.getClass() : "null") + " is not valid for" + node
            .getCode() + "." + element.getLabelID());
  }

//  public static IGspCommonField checkRefElementExists(
//      GspAssociation association, String labelId) {
//    if (association.getBelongElement().getLabelID().equalsIgnoreCase(labelId)) {
//      return (IGspCommonField) association.getBelongElement();
//    }
//    IGspCommonField field =
//        (IGspCommonField)
//            association.getRefElementCollection().stream()
//                .filter(item -> item.getLabelID().equalsIgnoreCase(labelId))
//                .findFirst()
//                .orElse(null);
//    if (field == null) {
//      throwRefElementNotFound(association, labelId);
//    }
//    return field;
//  }

  public static <TKey, TValue> HashMap<TKey, TValue> cloneForValues(HashMap<TKey, TValue> source)
      throws CloneNotSupportedException {
    if (source == null) {
      return null;
    }
    HashMap<TKey, TValue> result = new HashMap<>(source.size());
    for (Map.Entry<TKey, TValue> pair : source.entrySet()) {
      Object value = null;
      if (pair.getValue() == null) {
        value = null;
//      } else if (pair.getValue() instanceof AssociationInfo) {
//        value = ((AssociationInfo) pair.getValue()).clone();
      } else if (pair.getValue() instanceof ICefData) {
        value = ((ICefData) pair.getValue()).copySelf();
      } else {
        value = pair.getValue();
      }
      result.put(pair.getKey(), (TValue) value);
    }
    return result;
  }

  public static Stream<IGspCommonField> streamElements(IGspCommonDataType node,
      Predicate<IGspCommonField> predicate) {
    Stream<IGspCommonField> rez = node.getContainElements().stream();
    if (predicate != null) {
      rez = rez.filter(predicate);
    }
    return rez;
  }

  public static String getUdtConfigId(String udtId, String udtPackgeName) {
    GspMetadata udtMetadata = MetadataUtil.getCustomRTMetadata(udtId);
    UnifiedDataTypeDef udtContent = (UnifiedDataTypeDef) (udtMetadata != null ? udtMetadata
        .getContent() : null);
    if (udtContent == null) {
      throw new RuntimeException("udt元数据不存在" + udtId);
    }
    return udtContent.getUdtType();
  }

  public static void throwElementNotFound(IGspCommonDataType node, String labelId) {
    throw new RuntimeException("找不到字段" + node.getCode() + "." + labelId);
  }
}
